/**
 * 发现bug 
 * android app上字体要大于等于20px才能画多个字体,不然要每次调用fillText时都要设置字体
 * android app上,重绘时会一直闪烁
 * */
class canvasDraw {
	/*
	* @params{ DOM } canvasEl canvas元素节点
	* @params{ Object } option 统计图配置信息
	*/
	constructor(el, option) {
		// canvas DOM;
		this.option = option;
		this.context = el.context;
		// canvas宽高
		this.width = el.width;
		this.height = el.height;
		// 预留XY文字间距
		this.reservedSpace = 55;
		this.textAndDotSpace = 10;
		// X点之间的间隔 宽高
		this.spaceX = 1;
		this.spaceY = 70;
		this.xWidth = 1;
		this.xHeight = 1;
		
		this.XList = [];
		this.YList = [];

		let yAxis = this.option.yAxis || {};
		
		this.xAxis = this.option.xAxis.map(e => { 
			let date = new Date(e) 
			return date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日';
		})
		let measure = this.context.measureText(this.xAxis[0]).width;
		this.xAxisLength = measure || (this.width - this.reservedSpace) / 2;
		
		this.drawDataList = this.option.data || [];
		this.xScaleListLength = this.drawDataList[0] && this.drawDataList[0].data.length || 0;

		// 刻度数量
		this.scale = yAxis.subsection ? yAxis.subsection + 1 : 5;

		this.xScaleSizeOriginal = 0;

		// XY文字颜色  X线条点颜色 数据线颜色
		this.XYTextColor = '#666666';
		this.XDotColor = '#666666';
		this.dataLineXColor = this.option.dataLineXColor || [];
		if (this.dataLineXColor.length < this.xScaleListLength) {
			this.dataLineXColor = this.dataLineXColor.concat(
				[...Array(this.xScaleListLength - this.dataLineXColor.length).keys()]
				.map(e => this.getColor16())
			)
		}
		this.dataDotSize = 5;
		this.dataLineSize = 0.5;
		
		let data = this.drawDataList.length > 1 ? 
		this.drawDataList.map(e => e.data).reduce((a,b) => a.concat(b || [])) 
		: this.drawDataList[0].data;
		
		this.max = Math.max.apply(null, data);
		this.min = Math.min.apply(null, data);
		
		
		this.yScaleList = [];
		this.xScaleList = [];

		// 获取鼠标手势事件参数
		this.touchX = 0;
		this.touchY = 0;

		// 计数的做优化的值
		this.timeout = null;

		// 初始化
		this.init();

		// 绑定事件
		if(el.addEventListener){
			this.el.addEventListener('touchstart', touchstart, false);
			this.el.addEventListener('touchmove', touchmove, false);
			this.el.addEventListener('touchend', touchend, false);
			this.el.addEventListener('mouseout', mouseout, false);
			this.el.addEventListener('mousemove', mousemove, false);
		}
	}
	/**
	* 获取刻度数据
	* @return {Array} kedu
	*/
	getDatas(){
		let max =  this.max;
		let keduObject = this.keduObject = this.getMeanInfo();
		
		let kedu = [];
		if(keduObject.lose){
			for (let i = keduObject.lose; i > 0; i--) {
				if(keduObject.mean < 0){
					kedu.push(parseFloat((keduObject.mean * i).toFixed(2)));
				}else{
					kedu.push(parseFloat('-' + (keduObject.mean * i).toFixed(2)));
				}
			}
		}
		kedu.push(0)
		for (let i = 1, length = keduObject.just; i <= length; i++) {
			kedu.push(parseFloat((Math.abs(keduObject.mean) * i).toFixed(2)));
		}
		return kedu
	}
	/**
	* 刻度算法
	* @return {Number} 刻度大小
	*/
	meanFun(max, num = 4, bool) {
		if(max == 0 || num == 0){
			return 0
		}
		if(max < 0){
			Math.abs(max)
		}
		if (bool) {
			max = max.toFixed(2) * 100;
			return ((max + max % num) / num) / 100;
		}
		return Math.ceil((max + max % num) / num);
	}
	/**
	* 计算刻度数据
	* @return {Object} .just 正刻度量  .lose 负刻度量 .mean刻度大小
	*/
	getMeanInfo() {
		let max = this.max;
		let min = this.min;
		let subsection = this.scale - 1;
		
		let boolEan =  Math.floor(max) === Math.floor(min);
		
		if (max > 0 && min < 0) {
			let copyMin = Math.abs(min);
			let mean = this.meanFun(copyMin + max, subsection, boolEan);
			let bool = copyMin > max;
			let num = Math.floor([bool ? copyMin : max][0] / mean);
			let nMean = this.meanFun([bool ? copyMin : max][0], num, boolEan);
			
			return {
				just: bool ? subsection - num : num,
				mean: nMean,
				lose: !bool ? subsection - num : num
			}
		} else if (max >= 0 && min >= 0) {
			return {
				just: subsection,
				mean: this.meanFun(max, subsection,boolEan),
				lose: 0
			}
		} else if (max <= 0 && min < 0) {
			this.isLose = true;
			return {
				just: 0,
				mean: this.meanFun(min, subsection,boolEan),
				lose: subsection
			}
		}
	}
	/**
	* 初始化统计图
	*/
	init() {
		this.YText = this.getDatas().reverse();
		this.getYAxisList();
		this.getXAxisList();
		
		this.drawXYAxis();
		this.drawYText();
		this.drawXText();
		this.initData();
	}
	
	/**
	* 悬停线
	*/
	drawMouseTooltipLine() {
		if (!this.isTouch()) return;
		this.dataLineSize = 1;
		// this.redraw();
		this.drawMouseTooltipLineContext();
		this.drawMouseTooltip();
	}
	/**
	* 绘制悬停线
	*/
	drawMouseTooltipLineContext(){
		this.context.beginPath();
		this.context.strokeStyle = 'rgba(0,0,0,0.3)';
		this.context.lineTo(this.touchX, this.YList[0]);
		this.context.lineTo(this.touchX, this.YList[this.YList.length - 1]);
		this.context.stroke();
	}
	/**
	* 用于判断是否是在图指定区域里
	* @return {Boolean} true在指定区域里
	*/
	isTouch() {
		let XList = this.XList;
		let YList = this.YList;
		let touchX = this.touchX;
		let touchY = this.touchY;

		let maxX = XList[XList.length - 1];
		let minX = XList[0];
		let maxY = YList[YList.length - 1];
		let minY = YList[0];

		return (
			touchX >= minX && touchX <= maxX &&
			touchY >= minY && touchY <= maxY
		)
	}


	/**
	* 绘制悬停圈
	* 绘制坐标点数据
	*/
	drawMouseTooltip() {
		let XList = this.XList;
		let YList = this.YList;
		let touchX = this.touchX;
		let list = this.drawDataList;
		let fontTxtSize = this.fontTxtSize;
		let xScaleList = this.xScaleList;
		let yScaleList = this.yScaleList;
		let dataLineXColor = this.dataLineXColor;
		let lineHeight = this.lineHeight;
		let textIndent = this.textIndent;
		let minXValue = XList[0];
		let minYValue = YList[0];
		let xAxis = this.xAxis;

		let index = this.touchIndex = this.getBigValueMin(xScaleList, touchX);

		this.tooltipHeight = (fontTxtSize + lineHeight) * (list.length + 1) + lineHeight;
		
		list.forEach((e, i) => {
			
			this.context.beginPath();
			if(touchX > xScaleList[index] - 2 && touchX < xScaleList[index] + 2){
				this.context.fillStyle = dataLineXColor[i];
				this.context.globalAlpha=0.3;
				this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 2, 0, 2 * Math.PI);
				this.context.fill();
				
				this.context.beginPath();
				this.context.globalAlpha= 1;
				this.context.fillStyle = '#FFFFFF';
				this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 4 + 0.5, 0, 2 * Math.PI);
				this.context.fill();
				
				this.context.beginPath();
				this.context.globalAlpha= 1;
				this.context.fillStyle = dataLineXColor[i];
				this.context.arc(touchX, yScaleList[i][index], fontTxtSize / 4, 0, 2 * Math.PI);
				this.context.fill();
			}
			
		})
		
		// tip长度
		this.context.textAlign = 'start';
		this.context.textBaseline = 'middle';
		this.context.fillStyle = '#FFFFFF';
		let measure = this.context.measureText(xAxis[index]).width;
		this.tooltipWidth = measure ? measure + this.fontTxtSize * 2 : (this.width - this.reservedSpace) / 2;
		list.forEach((e, i) => {
			let dataTxt = e.data;
			let title = (e.title || '') + ':' + dataTxt[index];
			let measure = this.context.measureText(title).width;
			let tooltipWidth = measure ? measure + this.fontTxtSize * 2 : (this.width - this.reservedSpace) / 2;
			if(tooltipWidth > this.tooltipWidth){
				this.tooltipWidth = tooltipWidth;
			}
		})
		
		this.context.beginPath()
		this.context.fillStyle = 'rgba(255,255,255,1)';
		this.roundRect(minXValue, minYValue, this.tooltipWidth, this.tooltipHeight, 3);
		this.context.fill();
		
		this.context.beginPath()
		this.context.strokeStyle = 'rgba(220,65,55,1)';
		this.context.moveTo(minXValue, minYValue);
		this.context.lineTo(minXValue + this.tooltipWidth, minYValue);
		this.context.lineTo(minXValue + this.tooltipWidth, minYValue + this.tooltipHeight);
		this.context.lineTo(minXValue, minYValue + this.tooltipHeight);
		this.context.closePath()
		this.context.stroke();
		
		this.context.beginPath()
		this.context.fillStyle = '#333333';
		this.context.font = this.fontTxtSize + this.fontFamily;
		this.context.fillText(xAxis[index], minXValue + textIndent, minYValue + lineHeight + textIndent / 2, );
		let x = 0;
		let y = 0;
		list.forEach((e, i) => {
			this.context.beginPath();
			this.context.fillStyle = '#333333';
			let dataTxt = e.data;
			let title = (e.title || '') + ':' + dataTxt[index];
			x = minXValue + textIndent;
			y = minYValue + (fontTxtSize + lineHeight) * (i + 1) + textIndent / 2;
			this.context.font = this.fontTxtSize + this.fontFamily;
			this.context.fillText(title, x + textIndent * 2, y + lineHeight);
			
			this.context.beginPath();
			this.context.fillStyle = dataLineXColor[i];
			this.context.arc(x + textIndent / 2, y + lineHeight, fontTxtSize / 4, 0, 2 * Math.PI);
			this.context.fill();
		})
		// #ifdef H5
		setTimeout(() => {
			this.context.draw(true);
		},100)
		// #endif
		// #ifndef H5
		this.context.draw(true);
		// #endif
	}
	/**
	* 绘制圆角矩形
	*/
	roundRect(x, y, w, h, r) {
		if (w < 2 * r) r = w / 2;
		if (h < 2 * r) r = h / 2;
		this.context.beginPath();
		this.context.moveTo(x + r, y);
		this.context.arcTo(x + w, y, x + w, y + h, r);
		this.context.arcTo(x + w, y + h, x, y + h, r);
		this.context.arcTo(x, y + h, x, y, r);
		this.context.arcTo(x, y, x + w, y, r);
		this.context.closePath();
	}
	/**
	* 获取数据点下标
	*/
	getBigValueMin(array, x) {
		for (let i = 0, length = array.length; i < length; i++) {
			if (array[i] >= x) {
				return i;
			}
		}
		return array.length - 1;
	}
	/**
	* 获取数据对应坐标
	*/
	initData() {
		let YList = this.YList;
		let XList = this.XList;
		let YText = this.YText;
		let reservedSpace = this.reservedSpace;
		let xAxisLength = this.xAxisLength;
		// 刻度最大值最小值
		let minData = YText[YText.length - 1];
		let maxScaleList = YText[0];
		// 0坐标到Y刻度总高度的距离
		let XYHeight = YList[YList.length - 1];
		// Y刻度总高度
		let yHeight = XYHeight - this.spaceY;
		// x总刻度
		let xScaleAll = XList[XList.length - 1];
		// X每刻度大小
		this.xScaleSizeOriginal = this.xScaleSize = parseFloat(((xScaleAll - reservedSpace) / (this.xScaleListLength - 1)).toFixed(
			2));
		// y刻度每份大小
		let yScaleSize = this.yScaleSize = 0;
		// 当刻度最大值是0或者负数的时候
		if (YText[0] <= 0) {
			this.yScaleSize = yScaleSize = parseFloat((yHeight / (Math.abs(minData) - Math.abs(maxScaleList))).toFixed(8));
			this.drawDataList.forEach(data => {
				let list = data.data;
				this.yScaleList.push(list.map(e => Math.floor((Math.abs(e)) * yScaleSize + this.spaceY)));
			})
		} else {
			this.yScaleSize = yScaleSize = parseFloat((yHeight / (maxScaleList - minData)).toFixed(8));
			this.drawDataList.forEach(data => {
				let list = data.data;
				this.yScaleList.push(list.map(e => Math.floor((maxScaleList - e) * yScaleSize + this.spaceY)));
			})
		}

		this.drawDataLine();
	}
	/**
	* 重绘统计图 xy坐标轴 刻度文字 坐标线 统计线
	*/
	redraw() {
		this.context.clearRect(0, 0, this.width, this.height);
		this.drawXYAxis();
		this.drawYText();
		this.drawDataLine();
	}
	/**
	* 调节X坐标间距
	* @param {String,Number} size = [1-10] 
	*/
	handleXScaleSize(size) {
		this.xScaleSize = this.xScaleSizeOriginal * size;
		this.redraw();
	}
	/**
	* 绘制统计线
	*/
	drawDataLine() {
		let dataLineSize = this.dataLineSize;
		let dataDotSize = this.dataDotSize;
		let dataLineXColor = this.dataLineXColor;
		let reservedSpace = this.reservedSpace;
		let xScaleSize = this.xScaleSize;
		
		let YList = this.YList;
		let xScaleList = this.xScaleList = [...Array(this.xScaleListLength).keys()].map(i => Math.floor(i * xScaleSize + reservedSpace));
		
		this.context.lineJoin = 'round';
		
		let indexOf0 = this.YText.indexOf(0);
		let index0 = YList[indexOf0];
		let drawDataList = this.drawDataList;
		
		let gradient = this.context
		.createLinearGradient(this.xScaleList[0], YList[0], this.xScaleList[0], YList[YList.length - 1]);
		drawDataList.forEach((e, i) => {
			if(e.isBg){
				let bg = e.bgColor || [{ key:0, value: 'rgba(231, 0, 18, 0.5)' },{ key:1, value: 'rgba(231, 0, 18, 0.1)' }];
				if(typeof bg === 'string'){
					gradient = bg;
				}else{
					bg.forEach((ee,ii) => {
						gradient.addColorStop(ee.key, ee.value);
					})
				}
			}
		})
		this.context.fillStyle = gradient;
		this.yScaleList.forEach((yD, yI) => {
			for (var i = 1, length = xScaleList.length; i < length; i++) {
				let xx = this.xScaleList[i - 1];
				let xx1 = this.xScaleList[i];
				let yy = yD[i - 1];
				let yy1 = yD[i];
				let ax = (xx1 - xx) / 3;
				let bx = xx + ax;
				let bx1 = xx + ax * 2;
				
				this.context.beginPath();
				this.context.moveTo(xx, yy);
				this.context.bezierCurveTo(bx, yy, bx1, yy1, xx1, yy1);
				if(drawDataList[yI].isBg){
					this.context.lineTo(xx1, index0)
					this.context.lineTo(xx, index0)
					this.context.lineTo(xx, yy)
					this.context.fill();
				}
			}
		})
		this.context.lineWidth = this.dataLineSize;
		this.yScaleList.forEach((yD, yI) => {
			this.context.beginPath();
			this.context.strokeStyle = dataLineXColor[yI];
			for (var i = 1, length = xScaleList.length; i < length; i++) {
				let xx = this.xScaleList[i - 1];
				let xx1 = this.xScaleList[i];
				let yy = yD[i - 1];
				let yy1 = yD[i];
				let ax = (xx1 - xx) / 3;
				let bx = xx + ax;
				let bx1 = xx + ax * 2;
				
				this.context.moveTo(xx, yy);
				this.context.bezierCurveTo(bx, yy, bx1, yy1, xx1, yy1);
			}
			this.context.stroke();
		})
		// #ifdef H5
		setTimeout(() => {
			this.context.draw(true);
		},100)
		// #endif
		// #ifndef H5
		this.context.draw(true);
		// #endif
	}
	/**
	* 随机生成16位字符颜色
	*/
	getColor16() {
		return '#' + Math.random().toString(16).slice(-6);
	}
	/**
	* 绘制Y刻度文字
	*/
	drawYText() {
		let YText = this.YText;
		let YList = this.YList;
		let XYTextColor = this.XYTextColor;
		let reservedSpace = this.reservedSpace;
		let textAndDotSpace = this.textAndDotSpace;
		let x = reservedSpace - textAndDotSpace;
		
		
		this.context.fillStyle = XYTextColor;
		this.context.textAlign = 'end';
		this.context.textBaseline = 'middle';
		YList.forEach((y, i) => {
			this.context.font = this.fontTxtSize + this.fontFamily;
			this.context.fillText(this.YText[i], x, y, x);
		})
		this.drawXText();
	}
	/**
	* 绘制X刻度文字,由于时间问题,这里只绘制了起始和结束文字
	*/
	drawXText() {
		let xAxis = this.xAxis;
		let YList = this.YList;
		let XList = this.XList;
		let xAxisLength = this.xAxisLength;
		let XYTextColor = this.XYTextColor;
		let reservedSpace = this.reservedSpace;
		
		this.context.fillStyle = XYTextColor;
		
		this.context.textAlign = 'start';
		this.context.textBaseline = 'middle';
		this.context.font = this.fontTxtSize + this.fontFamily;
		this.context.fillText(xAxis[0], XList[0],
		YList[YList.length - 1] + this.fontTxtSize,
		xAxisLength + this.fontTxtSize * 4);
		this.context.font = this.fontTxtSize + this.fontFamily;
		this.context.textAlign = 'end';
		this.context.fillText(xAxis[xAxis.length - 1],
		XList[XList.length - 1], YList[YList.length - 1] + this.fontTxtSize,
		xAxisLength + this.fontTxtSize * 4);
		
		 
		// #ifdef H5
		setTimeout(() => {
			this.context.draw(true);
		},100)
		// #endif
		// #ifndef H5
		this.context.draw(true);
		// #endif
	}
	/**
	* 绘制XY统计图雏形
	*/
	drawXYAxis() {
		let XList = this.XList;
		let YList = this.YList;
		let xWidth = this.xWidth;
		let xHeight = this.xHeight;
		let XDotColor = this.XDotColor;
		let reservedSpace = this.reservedSpace;
		this.context.fillStyle = XDotColor;
		YList.forEach((y, i) => {
			XList.forEach((x, j) => {
				this.context.fillRect(x, y, xWidth, xHeight);
			})
		})
		// #ifdef H5
		setTimeout(() => {
			this.context.draw(true);
		},100)
		// #endif
		// #ifndef H5
		this.context.draw(true);
		// #endif
	}
	/**
	* 获取X轴对应坐标点
	*/
	getXAxisList() {
		let width = this.width;
		let spaceX = this.spaceX;
		let xWidth = this.xWidth;
		let xHeight = this.xHeight;
		
		let reservedSpace = this.reservedSpace;
		let length = (width - reservedSpace - this.fontTxtSize) / (xWidth + spaceX);
		for (let i = 0; i < length; i++) {
			this.XList.push(i * (spaceX + xWidth) + reservedSpace);
		}
	}
	/**
	* 获取y轴对应坐标点
	*/
	getYAxisList() {
		let height = this.height;
		let scale = this.scale;
		let reservedSpace = this.reservedSpace;
		this.spaceY = Math.floor((height - reservedSpace) / scale);
		for (let i = 0; i < scale; i++) {
			this.YList.push(i * this.spaceY + this.spaceY);
		}
		this.setTextStyle();
	}
	/**
	* 设置字体类型,行高,字体大小,缩进
	*/
	setTextStyle() {
		// 字体
		this.fontFamily = 'px 宋体';
		this.lineHeight = 10;
		this.textIndent = 10;
		this.fontTxtSize = this.spaceY / 5 < 14 ? 14 : this.spaceY / 5;
	}

};

let touchstart = function (e) {
	if (!e.touches[0]) return
	this.ctx.touchX = e.touches[0].x;
	this.ctx.touchY = e.touches[0].y;
	this.ctx.drawMouseTooltipLine()
}

let touchmove = function (e) {
	if (!e.touches[0]) return
	this.ctx.touchX = e.touches[0].x;
	this.ctx.touchY = e.touches[0].y;
	this.ctx.drawMouseTooltipLine()
}

let mousemove = function (e){
	if (e.pageX){
		this.ctx.touchX = e.x;
		this.ctx.touchY = e.y;
		this.ctx.drawMouseTooltipLine()
	}
}

let mouseout = function (e) {
	this.ctx.dataLineSize = 0.5;
	this.ctx.redraw()
}

let touchend = function (e) {
	this.ctx.dataLineSize = 0.5;
	this.ctx.redraw()
}

export default {
	canvasDraw,
	touchstart,
	touchmove,
	mousemove,
	mouseout,
	touchend
}